/**
 * 
 */
package any.note.server.resource;

import java.io.IOException;

import org.apache.commons.lang.StringUtils;
import org.restlet.Context;
import org.restlet.data.MediaType;
import org.restlet.data.Reference;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.data.Status;
import org.restlet.resource.Representation;
import org.restlet.resource.Resource;
import org.restlet.resource.ResourceException;
import org.restlet.resource.Variant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import any.note.Note;
import any.note.server.NoteService;
import any.restlet.helper.RepresentationHelper;

/**
 * Resource to handle operations on single note instance. <br/>
 * 
 * {@link NoteResource} can accept a number URI template combining together
 * different HTTP methods.
 * 
 * 
 * @author keke
 * @reversion $Revision: 34 $
 * @version 0.0.1
 * @see <a href="http://code.google.com/p/anysuites/wiki/AnyNoteResources">Any
 *      Note Protocol Design</a>
 */
public class NoteResource extends Resource {
    private static final Logger LOG = LoggerFactory
            .getLogger(NoteResource.class);
    private boolean allowPost;
    private Note note;
    private String noteId;
    private NoteService noteService;
    private RepresentationHelper repHelperManager;
    private String type;

    /*
     * (non-Javadoc)
     * 
     * @see org.restlet.resource.Resource#acceptRepresentation(org.restlet.resource.Representation)
     */
    @Override
    public void acceptRepresentation(final Representation entity)
            throws ResourceException {
        if (LOG.isDebugEnabled()) {
            LOG.debug("To Create a template note");
        }
        // at current moment, the entity body is ignored.
        final Note newNote = noteService.createNewNote();
        getResponse().setStatus(Status.REDIRECTION_TEMPORARY);
        getResponse().setLocationRef(
                new Reference(getRequest().getResourceRef().toString() + "/"
                        + newNote.getUuid()).getTargetRef());

    }

    @Override
    public boolean allowPost() {
        return allowPost;
    }

    @Override
    public void init(final Context context, final Request request,
            final Response response) {
        super.init(context, request, response);
        noteId = (String) request.getAttributes().get("noteid");
        allowPost = StringUtils.isEmpty(noteId);
        if (!allowPost) {
            // target is not null.
            note = noteService.getNote(noteId);
            setAvailable(note != null);
            type = (String) request.getAttributes().get("type");
            setModifiable(type == null);
            setReadable(type != null);
            if (LOG.isDebugEnabled()) {
                LOG.debug("Type of representation is {}", type);
            }
            getVariants().add(
                    new Variant(MediaType.valueOf(Utils.FILE_TYPE_MAP
                            .getContentType("Note." + type))));
        }
    }

    @Override
    public void removeRepresentations() throws ResourceException {
        noteService.delete(noteId);

    }

    /**
     * Get a Note representation. The URI template should be
     * <code>/note/{noteid}.{type}</code>, where the type indicates the
     * content type of returning representation.
     * 
     * @param variant -
     *            at current moment (v 0.0.1), supported types are
     *            {@code json, note}
     * @return an representation of existing note, or {@code null} and
     *         status(404) when note with specified id is not existed, or
     *         {@code null} with status(406) if requested content type is not
     *         supported.
     */
    @Override
    public Representation represent(final Variant variant)
            throws ResourceException {
        Representation result = null;
        final Note note = noteService.getNote(noteId);
        if (note != null) {
            result = repHelperManager.toRepresentation("note", note, variant);
            if (result == null) {
                // variant is not supported, mainly because requests a
                // unsupported mediaType.
                getResponse().setStatus(Status.CLIENT_ERROR_NOT_ACCEPTABLE);
            }
        } else {
            getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
        }
        return result;
    }

    public void setNoteService(final NoteService noteService) {
        this.noteService = noteService;
    }

    public void setRepHelperManager(final RepresentationHelper creatorManager) {
        repHelperManager = creatorManager;
    }

    @Override
    public void storeRepresentation(final Representation entity)
            throws ResourceException {
        if (LOG.isDebugEnabled()) {
            LOG.debug("To store {}", entity);
        }
        final Note.Status noteStatus = note.getStatus();
        try {
            noteService.save((Note) repHelperManager.toEntity("note", entity));
            if (noteStatus == Note.Status.NEW) {
                getResponse().setStatus(Status.SUCCESS_CREATED);
            }
        } catch (final IOException e) {
            throw new ResourceException(Status.SERVER_ERROR_INTERNAL, e);
        }
    }
}
